import time
import threading
from Helper import *
from multiprocessing import shared_memory

BasicInfo = "U2L-V2.1"
DeviceModel = "RS2carbus1-V1.6"
SerialNum = "s171705234ecc62b6"
class Channel:

    channelNum = 0

    isMainCtrl = 1   # 是否主控
    isSleep = 0     # 睡眠还是工作模式
    # 0：LIN协议V1.x 1：LIN协议V2.x 2：自动 3：K-line
    LINPolicyVer = 2
    errorCount = 0      # 错误计数
    SynTime = 0         # 同步时间戳
    busBuad = 19200     # 默认波特率
    RS232Buad = 115200  # 默认RS232波特率

    IDDataLength = []   # 每个ID的数据场长度
    IDResponseData = [bytearray(b'\x00') for i in range(64)] # 保存的所对应ID响应数据

    memName = "LINSim_Chn"
    memSetLock = threading.Lock()

    def __init__(self, channelNum):
        dataLen = [0x02 for i in range(0x1f)]
        self.IDDataLength.extend(dataLen)
        dataLen = [0x04 for i in range(0x2f)]
        self.IDDataLength.extend(dataLen)
        dataLen = [0x08 for i in range(0x3f)]
        self.IDDataLength.extend(dataLen)
        self.channelNum = channelNum
        self.memName += str(self.channelNum)

    def getTimeStamp(self):
        timeStamp = int(time.time() * 1000000).to_bytes(8, "little")[:4]
        return timeStamp

    class LINPackStruct:
        packCount = 0
        packLen = 0
        dataBuffer = None
        def toString(self):
            res = hexToStyledStr(self.packCount.to_bytes(4, byteorder='little'))
            res += hexToStyledStr(self.dataBuffer)

    class memGetPackageEvent:
        methodHandler = []
        @staticmethod
        def raiseEvent(*args):
            for func in Channel.memGetPackageEvent.methodHandler:
                func(*args)

    class memGetIdleEvent:
        methodHandler = []
        @staticmethod
        def raiseEvent(*args):
            for func in Channel.memGetIdleEvent.methodHandler:
                func(*args)

    def setMem(self, data):
        self.memSetLock.acquire()
        try:
            shm = shared_memory.SharedMemory(name=self.memName + "_Set", create=True, size=1500)
        except:
            shm = shared_memory.SharedMemory(name=self.memName + "_Set", size=1500)

        buf = shm.buf
        data_byteArr = self.structToBytearray(data)
        if data_byteArr == None:
            log("type of data is wrong", ERROR)
            self.memSetLock.release()
            return None
        buf = memoryview(data_byteArr)
        self.memSetLock.release()
        log("Send LIN package: " + data.toString(), INFO)

    def getMem(self):
        log("Get memory name is " + self.memName + "_Get", DEBUG)
        try:
            shm = shared_memory.SharedMemory(name=self.memName + "_Get", create=True, size=1500)
        except:
            shm = shared_memory.SharedMemory(name=self.memName + "_Get", size=1500)

        packageIndex = 0
        timeOut = 10
        while True:
            buf = shm.buf
            recvData = self.bytesToStruct(buf.tobytes())
            currentIndex = recvData.packCount
            timeOut -= 0.01
            if timeOut <= 0:
                timeOut = 10
                self.memGetIdleEvent.raiseEvent(self.channelNum)
            if currentIndex > packageIndex:
                packageIndex = currentIndex
                self.memGetPackageEvent.raiseEvent(self.channelNum, recvData)
                timeOut = 10
            time.sleep(0.01)

    def structToBytearray(self, struct):
        if type(struct) is not self.LINPackStruct:
            return None
        res = bytearray()
        res.extend(struct.packCount.to_byte(4, ))
        res.extend(struct.dataBuffer)
        return res

    def bytesToStruct(self, byteData):
        res = self.LINPackStruct()
        res.packCount = int.from_bytes(byteData[: 4], byteorder='little')
        res.packLen = int.from_bytes(byteData[4: 8], byteorder='little')
        res.dataBuffer = byteData[8: res.packLen + 8]
        return res



